//-------------------------------------------------------------------
//	Copyright (c) 2012-2014 Zhirnov Andrey
//	This file is part of the "UXGEN-ES" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#include "Graphics/Loaders/FontLoader.h"
#include "Graphics/MetaData/Meta.Font.h"
#include "Graphics/Systems/GraphicsEngine.h"

#define _INC_STDDEF
#define _INC_STRING
#define _INC_STDLIB
#define _INC_ERRNO
#define _INC_STDIO

#include <ft2build.h>
#include <freetype/freetype.h>

#include FT_FREETYPE_H
#include FT_GLYPH_H
#include FT_BITMAP_H
#include FT_TRUETYPE_TABLES_H


namespace Engine
{
namespace Graphics
{
	

//--------------------------- FontLoader --------------------------//
/*
=================================================
	constructor
=================================================
*/
	FontLoader::FontLoader () : _numChars(0), _ftLibrary(null)
	{
		CHECK( FT_Init_FreeType( (FT_Library *) &_ftLibrary ) == 0 );

		// Latin symbols (ANSI)
		_charCache.PushBack( uvec3( 33, 33, _numChars = 95 ) );
	}
	
/*
=================================================
	destructor
=================================================
*/
	FontLoader::~FontLoader ()
	{
		_vecFontMngr._Clear();

		if ( _ftLibrary != null )
		{
			FT_Done_FreeType( (FT_Library) _ftLibrary );
			_ftLibrary = null;
		}
	}
	
/*
=================================================
	Register
=================================================
*/
	void FontLoader::Register (ResourceManager *rm)
	{
		rm->RegisterLoader( EResource::BITMAP_FONT, LoadBitmapFontFromFile, LoadBitmapFontFromFName, this );
		rm->RegisterLoader( EResource::VECTOR_FONT, LoadVectorFontFromFile, null, this );
	}
	
/*
=================================================
	Unregister
=================================================
*/
	void FontLoader::Unregister (ResourceManager *rm)
	{
		rm->UnregisterLoader( EResource::BITMAP_FONT, LoadBitmapFontFromFile, LoadBitmapFontFromFName, this );
		rm->UnregisterLoader( EResource::VECTOR_FONT, LoadVectorFontFromFile, null, this );
	}

/*
=================================================
	Destroy
=================================================
*/
	void FontLoader::Destroy ()
	{
		_fb = null;
	}

/*
=================================================
	SetCharCache
=================================================
*/
	void FontLoader::SetCharCache (const char_intervals_t &charCache)
	{
		_charCache = charCache;

		FOR( i, _charCache ) {
			_numChars += _charCache[i].z;
		}
	}
	
/*
=================================================
	_LoadFontFT
=================================================
*/
	bool FontLoader::_LoadFontFT (ResourcePtr &resource, uni_c_string filename, void *parameter,
								  const Resource::ResLoadParams &loadParams, const EngineSubSystemsRef ess,
								  LoaderFunc_t loadFunc)
	{
		const uni_c_string	ext = FileAddressUtils::GetExtension( filename );

		if ( ext.ICmp( "ttf" ) )
		{
			FT_Face		face	= null;
			FontLoader&	loader	= *(FontLoader *)parameter;

			CHECK_ERR( FT_New_Face( (FT_Library) loader._ftLibrary, filename.cstr(), 0, &face ) == 0 );

			return (loader.*loadFunc)( resource, (FT_Face_t) face, loadParams, ess );
		}
		else
		{
			RFilePtr	file;
			ess->GetFileSystem()->OpenForRead( filename, file );

			return _LoadFontFT( resource, file, parameter, loadParams, ess, loadFunc );
		}
	}
		
/*
=================================================
	_LoadFontFT
=================================================
*/
	bool FontLoader::_LoadFontFT (ResourcePtr &resource, const RFilePtr &file, void *parameter,
								  const Resource::ResLoadParams &loadParams, const EngineSubSystemsRef ess,
								  LoaderFunc_t loadFunc)
	{
		bool	is_fnt = false;
		RESFILE_IS_HEADER( file, FontFileInfo, is_fnt );

		if ( is_fnt )
		{
			RESFILE_CHECK_HEADER( file, FontFileInfo );

			MetaData::VectorFontCfg		cfg;
			CHECK_ERR( cfg.Deserialize( file ) );
		}

		FT_Face		face	= null;
		FontLoader&	loader	= *(FontLoader *)parameter;

		binary_array_t	mem( file->RemainingSize() );

		CHECK_ERR( file->Read( mem.ptr(), mem.Size() ) );

		CHECK_ERR( FT_New_Memory_Face( (FT_Library) loader._ftLibrary, mem.ptr(), mem.Size(), 0, &face ) == 0 );
		
		return (loader.*loadFunc)( resource, (FT_Face_t) face, loadParams, ess );
	}

/*
=================================================
	_LoadBitmapFont
=================================================
*/
	bool FontLoader::_LoadBitmapFont (ResourcePtr &resource, FT_Face_t pface, const Resource::ResLoadParams &resLoadParams,
										const EngineSubSystemsRef ess)
	{
		FT_Face	face = (FT_Face) pface;

		CHECK_ERR( face != null );
		ASSERT( face->face_flags & FT_FACE_FLAG_SCALABLE );
		
		BitmapFont::BitmapFontLoadParams const &	loadParams = resLoadParams.To< BitmapFont::BitmapFontLoadParams >();

		const uint		size		 = loadParams.height;
		const uint		aligned_size = Align<4>( size + MARGIN_Y*2 );

		_glyphBuffer.Resize( aligned_size * aligned_size );

		CHECK_ERR( FT_Set_Pixel_Sizes( face, size, size ) == 0 );
		CHECK_ERR( FT_Select_Charmap( face, FT_ENCODING_UNICODE ) == 0 );
		

		// calculate font metrics
		int ascent  =  face->size->metrics.ascender >> 6;
		int descent = -face->size->metrics.descender >> 6;

		TT_OS2 * os2 = (TT_OS2 *) FT_Get_Sfnt_Table( face, ft_sfnt_os2 );

		if ( os2 != null )
		{
			ascent	= Max( ascent, os2->usWinAscent * face->size->metrics.y_ppem / face->units_per_EM );
			descent	= Max( descent, os2->usWinDescent * face->size->metrics.y_ppem / face->units_per_EM );

			ascent	= Max( ascent, os2->sTypoAscender * face->size->metrics.y_ppem / face->units_per_EM );
			descent	= Max( descent, -os2->sTypoDescender * face->size->metrics.y_ppem / face->units_per_EM );
		}

		int font_height = ascent + descent;


		// create texture
		uvec2	dim;
		{
			float	tex_square	= float(_numChars * font_height * font_height) * 0.6f;
			uint	quad_side	= CeilPowerOfTwo( uint( Sqrt( tex_square ) + 0.5f ) );
			uint	half_side	= quad_side >> 1;
			uint	quad_square	= Square( quad_side );
			uint	rect_square	= quad_side * half_side;

			if ( rect_square >= uint( tex_square + 0.5f ) and
				 rect_square <  quad_square )
			{
				dim = uvec2( quad_side, half_side );
			}
			else
				dim = uvec2( quad_side );
		}

		Sampler	sampler = Sampler::DefaultForRenderTarget();

		BitmapFontPtr font = BitmapFont::New( ess );

		font->_height = font_height;

		CHECK_ERR( font->GetTexture()->Alloc( uvec3(dim, 0), EPixelFormat::ALPHA8, 1 ) );
		font->GetTexture()->SetSampler( sampler );
		

		// clear texture
		/*FrameBuffer & fb = _GetFB( ess );

		fb.Bind();
		fb.Attach( *font->GetTexture(), gl_fbo_attach::COLOR );
		ess->GetGLStateManager()->PushViewport( ivec4( 0, 0, dim.x, dim.y ) );
		fb.ClearBuffers( color4f(0.0f) );
		fb.DetachAll();
		fb.Unbind();
		ess->GetGLStateManager()->PopViewport();*/
		

		// add glyphs
		uvec2	curr_pos( MARGIN_X, MARGIN_Y );
		uvec2	max_size;
		
		char_intervals_t const &	cache = _charCache;

		FOR( i, cache )
		{
			const uint	afirst	= cache[i].x;
			const uint	wfirst	= cache[i].y;
			const uint	count	= cache[i].z;

			for (uint j = 0; j < count; ++j)
			{
				const uint	symb = wfirst + j;
				const uint	code = afirst + j;

				ASSERT( symb <= 0xFFFF and code <= 0xFF );
				CHECK_ERR( _AddGlyph( font, pface, _glyphBuffer, curr_pos, max_size, uint16(symb), uint8(code)  ) );
			}
		}
		
		if ( loadParams.mipmaps )
		{
			font->GetTexture()->GenerateMipmaps();

			sampler.filter.min = gl_filter::LINEAR_MIPMAP_LINEAR;

			font->GetTexture()->SetSampler( sampler );
		}

		
		// add SPACE
		font->_glyphs[' '] = IFont::Glyph( max_size.x / (float)font->_height );
		
		// add TAB
		font->_glyphs['	'] = IFont::Glyph( max_size.x * 4 / (float)font->_height );

		FT_Done_Face( face );

		font->_CalcMemSize();

		resource = font;
		return true;
	}
	
/*
=================================================
	_AddGlyph
=================================================
*/
	bool FontLoader::_AddGlyph (BitmapFontPtr &font, FT_Face_t pface, binary_array_t &buf,
								uvec2 &pos, uvec2 &maxSize, uint16 symbol, uint8 code)
	{
		FT_Face	face = (FT_Face) pface;

		FT_GlyphSlot		slot		= face->glyph;
		FT_Glyph_Metrics	metrics		= slot->metrics;
		FT_UInt				char_index	= FT_Get_Char_Index( face, symbol );
		IFont::Glyph		glyph;
		
		CHECK_ERR( FT_Load_Glyph( face, char_index, FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT ) == 0 );

		uint		width	= font->_texture.Dimension().x;
		uint		height	= font->_texture.Dimension().y;
		uint		w		= slot->bitmap.width;
		uint		h		= slot->bitmap.rows;
		uint		align_w	= Align<4>( w + MARGIN_X*2 );
		uint		align_h	= Align<4>( h + MARGIN_Y*2 );

		if ( (pos.x + align_w) >= width ) {
			pos.x  = 0;
			pos.y += maxSize.y;
		}

		vec2		glyph_size	= vec2( w/(float)width, h/(float)height );
		vec2		glyph_pos	= (pos + uvec2(MARGIN_X, MARGIN_Y)).To<vec2>() / uvec2( width, height ).To<vec2>();
		uvec2 const	tex_pos		= pos;

		const float	scale		= 1.0f / font->_height;
		
		glyph.texcoord	 = rect( glyph_pos,  glyph_pos + glyph_size );
		glyph.offsetY	 = slot->bitmap_top * scale;
		glyph.offsetX[0] = slot->bitmap_left * scale;
		glyph.offsetX[1] = (slot->advance.x / 64.0f - int(w) - slot->bitmap_left) * scale;
		glyph.size		 = ivec2( w, h ).To<vec2>() * scale;
		glyph.empty		 = false;

		font->_baseLineTopMargin = Max(glyph.offsetY, font->_baseLineTopMargin);

		font->_glyphs[code] = glyph;
		pos.x += w + MARGIN_X*2;

		if ( w > maxSize.x )	maxSize.x = w;
		if ( h > maxSize.y )	maxSize.y = h;

		if ( (pos.y + align_h) >= height )
			RETURN_ERR( "Texture size is too small" );

		if ( slot->bitmap.buffer == null )
			RETURN_ERR( "Symbol " << uint(symbol) << "hasn't bitmap" );
		
		ASSERT( buf.Size() >= align_w * align_h );

		ZeroMem( buf.ptr(), buf.Size() );
		//MemSet( buf.ptr(), buf.Count(), uint8(255) );
		
		Memcpy2D( buf.ptr(), slot->bitmap.buffer, sizeof(uint8), align_w, align_h, w, h, MARGIN_X, MARGIN_Y );

		CHECK_ERR( font->_texture.AddImage( uvec3( tex_pos, 0 ), uvec3( align_w, align_h, 0 ),
												EPixelFormat::ALPHA8, 0, buf ) );

		if ( FT_Load_Glyph( face, char_index, FT_LOAD_RENDER | FT_LOAD_NO_HINTING ) == 0 )
		{
			glyph.offsetX[1] = (face->glyph->advance.x / 64.0f - int(w)) * scale - glyph.offsetX[0];
		}
		return true;
	}
	
/*
=================================================
	_LoadVectorFont
=================================================
*/
	bool FontLoader::_LoadVectorFont (ResourcePtr &resource, const RFilePtr &file, void *parameter,
									  const VectorFont::VectorFontLoadParams &loadParams, const EngineSubSystemsRef ess)
	{
		RESFILE_CHECK_HEADER( file, FontFileInfo );

		MetaData::VectorFontCfg		cfg;
		CHECK_ERR( cfg.Deserialize( file ) );
		
		VectorFontPtr	font = VectorFont::New( ess );
		
		FT_Face		face	= null;
		FontLoader&	loader	= *(FontLoader *)parameter;

		MemRFilePtr	mem_file;

		if ( file->GetType() == File::EFile::MEMORY )
		{
			mem_file = file;
		}
		else
		{
			CHECK_ERR( ess->GetFileSystem()->ReadToMem( file, (RFilePtr &) mem_file ) );
		}

		uni_binbuffer_t	mem = mem_file->GetData();

		CHECK_ERR( FT_New_Memory_Face( (FT_Library) loader._ftLibrary, mem.ptr(), mem.Size(), 0, &face ) == 0 );
		
		CHECK_ERR( face != null );
		ASSERT( face->face_flags & FT_FACE_FLAG_SCALABLE );

		font->_fontFreeType			= new VectorFontManager::FontFace( mem_file, (FT_Face_t) face );
		font->_baseLineTopMargin	= cfg.baseLineTopMargin;

		loader._vecFontMngr._faces.Add( file->Name(), font->_fontFreeType );

		resource = font;
		return true;
	}
	
/*
=================================================
	_LoadGlyph
=================================================
*/
	bool FontLoader::_LoadGlyph (FT_Face_t tface, uint8 symbol, uint height, const uvec2 &texDim,
								 OUT VectorFont::VecGlyph &glyph, OUT uvec2 &imageDim, OUT uni_binbuffer_t &image)
	{
		const float	space_width = 0.6f;

		if ( symbol == ' ' )	// space
		{
			glyph = VectorFont::VecGlyph( space_width );
			glyph.loaded = true;
			image = uni_binbuffer_t();
			return true;
		}
		
		if ( symbol == '	' )	// tab
		{
			glyph = VectorFont::VecGlyph( space_width * 4 );
			glyph.loaded = true;
			image = uni_binbuffer_t();
			return true;
		}


		uint	symb = 0;
		{
			char_intervals_t const &	cache = _charCache;

			FOR( i, cache )
			{
				if ( symbol >= cache[i].x and symbol <= cache[i].x + cache[i].z )
				{
					symb = cache[i].y - cache[i].x + symbol;
					break;
				}
			}
			CHECK_ERR( symb != 0 );
		}
		
		FT_Face	face = (FT_Face) tface;
		
		CHECK_ERR( FT_Set_Pixel_Sizes( face, height, height ) == 0 );
		CHECK_ERR( FT_Select_Charmap( face, FT_ENCODING_UNICODE ) == 0 );

		FT_UInt		char_index		= FT_Get_Char_Index( face, uint16(symb) );
		
		ASSERT( char_index != 0 );
		CHECK_ERR( FT_Load_Glyph( face, char_index, FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT ) == 0 );
		
		// calculate font metrics
		int ascent  =  face->size->metrics.ascender >> 6;
		int descent = -face->size->metrics.descender >> 6;

		TT_OS2 * os2 = (TT_OS2 *) FT_Get_Sfnt_Table( face, ft_sfnt_os2 );

		if ( os2 != null )
		{
			ascent	= Max( ascent, os2->usWinAscent * face->size->metrics.y_ppem / face->units_per_EM );
			descent	= Max( descent, os2->usWinDescent * face->size->metrics.y_ppem / face->units_per_EM );

			ascent	= Max( ascent, os2->sTypoAscender * face->size->metrics.y_ppem / face->units_per_EM );
			descent	= Max( descent, -os2->sTypoDescender * face->size->metrics.y_ppem / face->units_per_EM );
		}

		int font_height = ascent + descent;


		FT_GlyphSlot		slot	= face->glyph;
		FT_Glyph_Metrics	metrics	= slot->metrics;

		uint const	w			 = slot->bitmap.width;
		uint const	h			 = slot->bitmap.rows;
		uint const	align_w		 = Align<4>( w + MARGIN_X*2 );
		uint const	align_h		 = Align<4>( h + MARGIN_Y*2 );

		imageDim = uvec2(align_w, align_h);

		_glyphBuffer.Resize( align_w * align_h );
		image	 = (uni_binbuffer_t) _glyphBuffer;

		vec2 const	dim			= texDim.To<vec2>();
		vec2 const	inv_dim		= 1.0f / dim;
		vec2 const	glyph_size	= vec2( float(w+1), float(h+1) ) * inv_dim;
		vec2 const	sub_texel	= 0.5f * inv_dim;
		float const	scale		= 1.0f / font_height;
		
		glyph.texcoord		= rect( -sub_texel, sub_texel + glyph_size );
		glyph.offsetY		= slot->bitmap_top * scale;
		glyph.offsetX[0]	= slot->bitmap_left * scale;
		glyph.offsetX[1]	= (slot->advance.x / 64.0f - int(w) - slot->bitmap_left) * scale;
		glyph.size			= ivec2( w, h ).To<vec2>() * scale;
		glyph.empty			= false;
		glyph.loaded		= true;
		
		if ( slot->bitmap.buffer == null )
			RETURN_ERR( "Symbol " << uint(symbol) << " hasn't bitmap" );
		
		ASSERT( image.Size() >= align_w * align_h );

		ZeroMem( _glyphBuffer.ptr(), _glyphBuffer.Size() );

		Memcpy2D( _glyphBuffer.ptr(), slot->bitmap.buffer, sizeof(uint8), align_w, align_h, w, h, MARGIN_X, MARGIN_Y );

		if ( FT_Load_Glyph( face, char_index, FT_LOAD_RENDER | FT_LOAD_NO_HINTING ) == 0 )
		{
			glyph.offsetX[1] = (face->glyph->advance.x / 64.0f - int(w)) * scale - glyph.offsetX[0];
		}
		return true;
	}

/*
=================================================
	_GetFB
=================================================
*/
	FrameBuffer &  FontLoader::_GetFB (const EngineSubSystemsRef ess)
	{
		if ( _fb.IsNull() )
		{
			_fb = FrameBuffer::New( ess );
			_fb->Create();
		}

		return *_fb.ptr();
	}

/*
=================================================
	LoadBitmapFontFromFName
=================================================
*/
	bool FontLoader::LoadBitmapFontFromFName (ResourcePtr &resource, uni_c_string filename, void *parameter,
											  const Resource::ResLoadParams &loadParams, const EngineSubSystemsRef ess)
	{
		CHECK_ERR( loadParams.Is< BitmapFont::BitmapFontLoadParams >() );

		return _LoadFontFT( resource, filename, parameter, loadParams, ess, &FontLoader::_LoadBitmapFont );
	}

/*
=================================================
	LoadBitmapFontFromFile
=================================================
*/
	bool FontLoader::LoadBitmapFontFromFile (ResourcePtr &resource, const RFilePtr &file, void *parameter,
											 const Resource::ResLoadParams &loadParams, const EngineSubSystemsRef ess)
	{
		CHECK_ERR( loadParams.Is< BitmapFont::BitmapFontLoadParams >() );

		return _LoadFontFT( resource, file, parameter, loadParams, ess, &FontLoader::_LoadBitmapFont );
	}
	
/*
=================================================
	LoadVectorFontFromFile
=================================================
*/
	bool FontLoader::LoadVectorFontFromFile (ResourcePtr &resource, const RFilePtr &file, void *parameter,
											 const Resource::ResLoadParams &loadParams, const EngineSubSystemsRef ess)
	{
		CHECK_ERR( loadParams.Is< VectorFont::VectorFontLoadParams >() );

		return _LoadVectorFont( resource, file, parameter, loadParams.To< VectorFont::VectorFontLoadParams >(), ess );
	}
	
/*
=================================================
	CreateLevel
=================================================
*/
	bool FontLoader::CreateLevel (Ptr< VectorFont > font, uint height)
	{
		return _vecFontMngr._CreateLevel( font, height );
	}
	
/*
=================================================
	LoadGlyph
=================================================
*/
	bool FontLoader::LoadGlyph (Ptr< VectorFont > font, uint8 symbol, uint height, OUT VectorFont::VecGlyph &glyph)
	{
		return _vecFontMngr._LoadGlyph( font, symbol, height, glyph );
	}
	
/*
=================================================
	DestroyLevel
=================================================
*/
	bool FontLoader::DestroyLevel (Ptr< VectorFont > font, uint height)
	{
		return _vecFontMngr._DestroyLevel( font, height );
	}

/*
=================================================
	DestroyFontLevels
=================================================
*/
	bool FontLoader::DestroyFontLevels (Ptr< VectorFont > font)
	{
		return _vecFontMngr._DestroyFontLevels( font );
	}




//------------------------- VectorFontManager ---------------------//
/*
=================================================
	_LoadGlyph
=================================================
*/
	inline bool VectorFontManager::_LoadGlyph (Ptr< VectorFont > font, uint8 symbol, uint height, OUT IFont::Glyph &glyph)
	{
		uvec2 const		tex_dim = uvec2( _ATLAS_WIDTH, _ATLAS_HEIGHT );
		uvec2			image_dim;
		uvec2			pos;
		uni_binbuffer_t	image;
		
		VectorFont::VecGlyph &	vec_glyph = (VectorFont::VecGlyph &) glyph;

		CHECK_ERR( font->GetSubSystems()->GetGraphicsEngine()->GetFontLoader()->
						_LoadGlyph( font->_fontFreeType->GetFace(), symbol, height,
									tex_dim, vec_glyph, image_dim, image ) );

		font_lines_map_t::iterator	res;

		bool	found_full_line = false;

		while ( true )
		{
			CHECK_ERR( _lines.Find( AnyFontTex( font, height + _MARGIN ), res ) );

			if ( res->first.isFull )
			{
				CHECK_ERR( not found_full_line );

				// create new line
				found_full_line = true;
				CHECK_ERR( _CreateLevel( font, height ) );
				continue;
			}

			TexLine	const &	tl = res->second;

			if ( vec_glyph.empty and image.Empty() )
			{
				vec_glyph.texture = &tl.atlas->tex;
				return true;
			}

			if ( not tl.atlas->atlas.AddTexture( tl.line, image_dim, pos ) )
			{
				AllocFontTex	f = res->first;
				f.isFull = true;

				found_full_line = false;

				_lines.ChangeKey( f, res );
				continue;
			}

			glyph.texcoord += ( (pos + uvec2(_MARGIN_X, _MARGIN_Y)).To<vec2>() / tex_dim.To<vec2>() );

			CHECK_ERR( tl.atlas->tex.AddImage( uvec3( pos, 0 ), uvec3( image_dim, 0 ),
													EPixelFormat::ALPHA8, 0, image ) );
			
			vec_glyph.texture = &tl.atlas->tex;
			return true;
		}

		RETURN_ERR( "unknown" );
	}
	
/*
=================================================
	_CreateLevel
=================================================
*/
	bool VectorFontManager::_CreateLevel (Ptr< VectorFont > font, uint height)
	{
		CHECK_ERR( font.IsNotNull() and height > 0 );

		height += _MARGIN;

		FindAnyFont	cmp( font );
		usize		idx = -1;

		// search atlas for font
		if ( _lines.FindIndex( cmp, idx ) )
		{
			for (usize i = idx; i < _lines.Count(); ++i)
			{
				if ( not ( cmp == _lines[i].first ) )
					break;

				TexLine const &	tl = _lines[i].second;
				
				atlas_tex_id_t	line;

				if ( tl.atlas->atlas.AllocLine( line, uvec2( _lineWidth, height ) ) )
				{
					_lines.Add( AllocFontTex( font, height ), TexLine( tl.atlas, line ) );
					return true;
				}
			}
		}

		// search any atlas
		FOR( i, _atlases )
		{
			atlas_tex_id_t	line;

			if ( _atlases[i]->atlas.AllocLine( line, uvec2( _lineWidth, height ) ) )
			{
				_lines.Add( AllocFontTex( font, height ), TexLine( _atlases[i], line ) );
				return true;
			}
		}


		// create new atlas
		Sampler const	sampler = Sampler::DefaultForRenderTarget();

		TexAtlasPtr	atlas = new TexAtlas( font->GetSubSystems() );
		
		atlas_tex_id_t	line;
		uvec2 const		dim = uvec2( _ATLAS_WIDTH, _ATLAS_HEIGHT );

		CHECK_ERR( atlas->atlas.Create( dim ) );
		CHECK_ERR( atlas->tex.Alloc( uvec3( atlas->atlas.Dimension(), 0 ), EPixelFormat::ALPHA8, 1 ) );

		atlas->tex.SetSampler( sampler );
		CHECK_ERR( atlas->atlas.AllocLine( line, uvec2( _lineWidth, height ) ) );


		_lines.Add( AllocFontTex( font, height ), TexLine( atlas, line ) );
		_atlases.PushBack( atlas );
		return true;
	}
	



//---------------------------- FontFace ---------------------------//
/*
=================================================
	destructor
=================================================
*/
	VectorFontManager::FontFace::~FontFace ()
	{
		FT_Done_Face( (FT_Face) _face );
	}


}	// Graphics
}	// Engine